#include "fd_manager.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

FdCtx::FdCtx(int fd)
    :m_isInit(false)
    ,m_isSocket(false)
    ,m_sysNonblock(false)
    ,m_userNonblock(false)
    ,m_isClosed(false)
    ,m_fd(fd)
    ,m_recvTimeout(-1)
    ,m_sendTimeout(-1) {
    init();
}

FdCtx::~FdCtx() {
}

bool FdCtx::init() {
    if(m_isInit) { //是否已经初始化
        return true;
    }
    m_recvTimeout = -1; //重置
    m_sendTimeout = -1;

    struct stat fd_stat;    //定义一个stat结构体
    if(-1 == fstat(m_fd, &fd_stat)) { //fstat查看文件是否是句柄 -1表示失败
        m_isInit = false;
        m_isSocket = false;
    } else {
        m_isInit = true;
        m_isSocket = S_ISSOCK(fd_stat.st_mode); //检查一个文件描述符（通常表示一个打开的文件、套接字或目录等）是否表示一个套接字（socket）
    }

    if(m_isSocket) {
        int flags = fcntl_f(m_fd, F_GETFL, 0); //使用原始函数取出flags
        if(!(flags & O_NONBLOCK)) { //如果不是非阻塞的
            fcntl_f(m_fd, F_SETFL, flags | O_NONBLOCK); //改为非阻塞
        }
        m_sysNonblock = true; //标志非阻塞
    } else {
        m_sysNonblock = false; //标志为阻塞
    }

    m_userNonblock = false;
    m_isClosed = false;
    return m_isInit;
}

//设置句柄的超时时间
void FdCtx::setTimeout(int type, uint64_t v) {
    if(type == SO_RCVTIMEO) { //如果是读
        m_recvTimeout = v; //设置读超时时间
    } else {
        m_sendTimeout = v; //设置写超时时间
    }
}

uint64_t FdCtx::getTimeout(int type) {
    if(type == SO_RCVTIMEO) {
        return m_recvTimeout; //返回读超时时间
    } else {
        return m_sendTimeout; //返回写超时时间
    }
}

FdManager::FdManager() {
    m_datas.resize(64); 
}

//获取到句柄
FdCtx::ptr FdManager::get(int fd, bool auto_create) {
    if(fd == -1) {
        return nullptr;
    }
    RWMutexType::readLock lock(m_mutex);
    if((int)m_datas.size() <= fd) { //不存在
        if(auto_create == false) { //并且不是自动创建
            return nullptr;
        }
    } else {
        if(m_datas[fd] || !auto_create) { //不用创建
            return m_datas[fd]; //返回句柄
        }
    }
    lock.unlock();

    RWMutexType::writeLock lock2(m_mutex);
    FdCtx::ptr ctx(new FdCtx(fd)); //开始创建
    if(fd >= (int)m_datas.size()) { 
        m_datas.resize(fd * 1.5); //重置容器大小
    }
    m_datas[fd] = ctx; //添加到容器中
    return ctx;
}

void FdManager::del(int fd) {
    RWMutexType::writeLock lock(m_mutex);
    if((int)m_datas.size() <= fd) { //表示本身不存在
        return;
    }
    m_datas[fd].reset(); //把容器重置
}

